<template>
  <div class="editContainer">
    <div class="mindMapContainer" ref="mindMapContainer"></div>
    <!--左下角的计数器    -->
    <Count :mindMap="mindMap" v-if="!isZenMode" />
    <!-- 右下角导航小地图   -->
    <Navigator :mindMap="mindMap" />
    <!-- 右键小菜单   -->
    <Contextmenu v-if="mindMap" :mindMap="mindMap" />
    <!--右下角的工具栏    -->
    <NavigatorToolbar :mindMap="mindMap" v-if="!isZenMode" />
    <!-- 搜索框   -->
    <Search v-if="mindMap" :mindMap="mindMap" />
    <!--右边操作栏    -->
    <SidebarTrigger v-if="!isZenMode" />
    <!--样式    -->
    <NodeStyle v-if="!isZenMode" />
    <!--基础样式  -->
    <BaseStyle :data="mindMapData" :mindMap="mindMap" />
    <!--主题选择-->
    <Theme v-if="mindMap" :mindMap="mindMap" />
    <!--结构选择-->
    <Structure :mindMap="mindMap" />
    <!-- 大纲侧边栏   -->
    <OutlineSidebar :mindMap="mindMap" />
    <!-- 大纲的编辑模式   -->
    <OutlineEdit v-if="mindMap" :mindMap="mindMap" />
    <!--快捷键-->
    <ShortcutKey />
    <!--图片预览    -->
    <NodeImgPreview v-if="mindMap" :mindMap="mindMap" />
    <!-- 图标的右侧弹窗 通过node.setIcon进行图标设置-->
    <NodeIconSidebar v-if="mindMap" :mindMap="mindMap" />
    <!-- 节点上点击小图标之后 的弹窗主要是可以修改同类型下的图标也可以删除图标    -->
    <NodeIconToolbar v-if="mindMap" :mindMap="mindMap" />
    <!-- 选中节点内容后增加富文本编辑的框   -->
    <RichTextToolbar v-if="mindMap" :mindMap="mindMap" />
    <!-- 节点上记录的笔记  鼠标移上去显示笔记详情弹窗   -->
    <NodeNoteContentShow v-if="mindMap" :mindMap="mindMap" />
    <!--公式弹窗    -->
    <FormulaSidebar v-if="mindMap" :mindMap="mindMap" />
    <Scrollbar v-if="isShowScrollbar && mindMap" :mindMap="mindMap"></Scrollbar>
  </div>
</template>

<script>
import MindMap from 'simple-mind-map'
import MiniMap from 'simple-mind-map/src/plugins/MiniMap.js'
import Watermark from 'simple-mind-map/src/plugins/Watermark.js'
import KeyboardNavigation from 'simple-mind-map/src/plugins/KeyboardNavigation.js'
import ExportPDF from 'simple-mind-map/src/plugins/ExportPDF.js'
import ExportXMind from 'simple-mind-map/src/plugins/ExportXMind.js'
import Export from 'simple-mind-map/src/plugins/Export.js'
import Drag from 'simple-mind-map/src/plugins/Drag.js'
import Select from 'simple-mind-map/src/plugins/Select.js'
import RichText from 'simple-mind-map/src/plugins/RichText.js'
import AssociativeLine from 'simple-mind-map/src/plugins/AssociativeLine.js'
import TouchEvent from 'simple-mind-map/src/plugins/TouchEvent.js'
import NodeImgAdjust from 'simple-mind-map/src/plugins/NodeImgAdjust.js'
import SearchPlugin from 'simple-mind-map/src/plugins/Search.js'
import Painter from 'simple-mind-map/src/plugins/Painter.js'
import ScrollbarPlugin from 'simple-mind-map/src/plugins/Scrollbar.js'
import Formula from 'simple-mind-map/src/plugins/Formula.js'
import Count from './Count.vue'
import Contextmenu from './Contextmenu.vue'
import NavigatorToolbar from './NavigatorToolbar.vue'
import Search from './Search.vue'
import SidebarTrigger from './SidebarTrigger.vue'
import Style from './Style.vue'
import Theme from './Theme.vue'
import Structure from './Structure.vue'
import OutlineSidebar from './OutlineSidebar.vue'
import OutlineEdit from './OutlineEdit.vue'
import ShortcutKey from './ShortcutKey.vue'
import BaseStyle from './BaseStyle.vue'
import RichTextToolbar from './RichTextToolbar.vue'
import NodeNoteContentShow from './NodeNoteContentShow.vue'
import { getData, storeData, storeConfig } from '@/api'
import Navigator from './Navigator.vue'
import NodeImgPreview from './NodeImgPreview.vue'
import { mapState } from 'pinia'
import icon from '@/config/icon.js'
import customThemeList from '@/customThemes/index.js'
import NodeIconSidebar from './NodeIconSidebar.vue'
import NodeIconToolbar from './NodeIconToolbar.vue'
import { showLoading, hideLoading } from '@/utils/loading.js'
import handleClipboardText from '@/utils/handleClipboardText.js'
import Scrollbar from './Scrollbar.vue'
import exampleData from 'simple-mind-map/example/exampleData'
import FormulaSidebar from './FormulaSidebar.vue'
import { useMindStore } from '@/stores/useMindStore.js'
import bus from '@/utils/bus.js'

// 注册插件
MindMap.usePlugin(MiniMap)
  .usePlugin(Watermark)
  .usePlugin(Drag)
  .usePlugin(KeyboardNavigation)
  .usePlugin(ExportPDF)
  .usePlugin(ExportXMind)
  .usePlugin(Export)
  .usePlugin(Select)
  .usePlugin(AssociativeLine)
  .usePlugin(NodeImgAdjust)
  .usePlugin(TouchEvent)
  .usePlugin(SearchPlugin)
  .usePlugin(Painter)
  .usePlugin(Formula)
// .usePlugin(Cooperate)// 协同插件

// 注册自定义主题
customThemeList.forEach(item => {
  MindMap.defineTheme(item.value, item.theme)
})

/**
 * @Author: 王林
 * @Date: 2021-06-24 22:56:17
 * @Desc: 编辑区域
 */
export default {
  name: 'EditContent',
  components: {
    Count,
    Navigator,
    Contextmenu,
    NavigatorToolbar,
    Search,
    SidebarTrigger,
    NodeStyle: Style,
    BaseStyle,
    OutlineSidebar,
    OutlineEdit,
    ShortcutKey,
    Theme,
    Structure,
    NodeImgPreview,
    NodeIconSidebar,
    NodeIconToolbar,
    RichTextToolbar,
    NodeNoteContentShow,
    FormulaSidebar,
    Scrollbar
  },
  data() {
    return {
      enableShowLoading: true,
      mindMap: null,
      mindMapData: null,
      prevImg: '',
      storeConfigTimer: null
    }
  },
  computed: {
    ...mapState(useMindStore, {
      isZenMode: state => state.localConfig.isZenMode,
      openNodeRichText: state => state.localConfig.openNodeRichText,
      isShowScrollbar: state => state.localConfig.isShowScrollbar,
      useLeftKeySelectionRightKeyDrag: state =>
        state.localConfig.useLeftKeySelectionRightKeyDrag,
      isUseHandDrawnLikeStyle: state =>
        state.localConfig.isUseHandDrawnLikeStyle
    })
  },
  watch: {
    openNodeRichText() {
      if (this.openNodeRichText) {
        this.addRichTextPlugin()
      } else {
        this.removeRichTextPlugin()
      }
    },
    isShowScrollbar() {
      if (this.isShowScrollbar) {
        this.addScrollbarPlugin()
      } else {
        this.removeScrollbarPlugin()
      }
    },
    isUseHandDrawnLikeStyle() {
      if (this.isUseHandDrawnLikeStyle) {
        this.addHandDrawnLikeStylePlugin()
      } else {
        this.removeHandDrawnLikeStylePlugin()
      }
    }
  },
  mounted() {
    showLoading()
    this.getData()
    this.init()
    bus.on('execCommand', this.execCommand)
    bus.on('paddingChange', this.onPaddingChange)
    bus.on('export', this.export)
    bus.on('setData', this.setData)
    bus.on('startTextEdit', this.handleStartTextEdit)
    bus.on('endTextEdit', this.handleEndTextEdit)
    bus.on('createAssociativeLine', this.handleCreateLineFromActiveNode)
    bus.on('startPainter', this.handleStartPainter)
    bus.on('node_tree_render_end', this.handleHideLoading)
    bus.on('showLoading', this.handleShowLoading)
    window.addEventListener('resize', this.handleResize)
  },
  unmounted() {
    bus.off('execCommand', this.execCommand)
    bus.off('paddingChange', this.onPaddingChange)
    bus.off('export', this.export)
    bus.off('setData', this.setData)
    bus.off('startTextEdit', this.handleStartTextEdit)
    bus.off('endTextEdit', this.handleEndTextEdit)
    bus.off('createAssociativeLine', this.handleCreateLineFromActiveNode)
    bus.off('startPainter', this.handleStartPainter)
    bus.off('node_tree_render_end', this.handleHideLoading)
    bus.off('showLoading', this.handleShowLoading)
    window.removeEventListener('resize', this.handleResize)
    this.mindMap.destroy()
  },
  methods: {
    handleStartTextEdit() {
      this.mindMap.renderer.startTextEdit()
    },

    handleEndTextEdit() {
      this.mindMap.renderer.endTextEdit()
    },

    handleCreateLineFromActiveNode() {
      this.mindMap.associativeLine.createLineFromActiveNode()
    },

    handleStartPainter() {
      this.mindMap.painter.startPainter()
    },

    handleResize() {
      this.mindMap.resize()
    },

    // 显示loading
    handleShowLoading() {
      this.enableShowLoading = true
      showLoading()
    },

    // 渲染结束后关闭loading
    handleHideLoading() {
      if (this.enableShowLoading) {
        this.enableShowLoading = false
        hideLoading()
      }
    },

    /**
     * @Author: 王林
     * @Date: 2021-07-03 22:11:37
     * @Desc: 获取思维导图数据，实际应该调接口获取
     */
    getData() {
      this.mindMapData = getData()
    },

    /**
     * @Author: 王林
     * @Date: 2021-08-01 10:19:07
     * @Desc: 存储数据当数据有变时
     */
    bindSaveEvent() {
      bus.on('data_change', data => {
        storeData(data)
      })
      bus.on('view_data_change', data => {
        clearTimeout(this.storeConfigTimer)
        this.storeConfigTimer = setTimeout(() => {
          storeConfig({
            view: data
          })
        }, 300)
      })
    },

    /**
     * @Author: 王林
     * @Date: 2021-08-02 23:19:52
     * @Desc: 手动保存
     */
    manualSave() {
      let data = this.mindMap.getData(true)
      storeConfig(data)
    },

    /**
     * @Author: 王林
     * @Date: 2021-04-10 15:01:01
     * @Desc: 初始化
     */
    init() {
      let hasFileURL = this.hasFileURL()
      let { root, layout, theme, view, config } = this.mindMapData
      // 如果url中存在要打开的文件，那么思维导图数据、主题、布局都使用默认的
      if (hasFileURL) {
        root = {
          data: {
            text: this.$t('edit.root')
          },
          children: []
        }
        layout = exampleData.layout
        theme = exampleData.theme
        view = null
      }
      this.mindMap = new MindMap({
        el: this.$refs.mindMapContainer,
        data: root,
        fit: false,
        layout: layout,
        theme: theme.template,
        themeConfig: theme.config,
        viewData: view,
        nodeTextEditZIndex: 1000,
        nodeNoteTooltipZIndex: 1000,
        customNoteContentShow: {
          show: (content, left, top, node) => {
            bus.emit('showNoteContent', content, left, top, node)
          },
          hide: () => {
          }
        },
        ...(config || {}),
        iconList: [...icon],
        useLeftKeySelectionRightKeyDrag: this.useLeftKeySelectionRightKeyDrag,
        customInnerElsAppendTo: null,
        enableAutoEnterTextEditWhenKeydown: true,
        customHandleClipboardText: handleClipboardText,
        defaultNodeImage: import('../../../assets/img/图片加载失败.svg'),
        initRootNodePosition: ['center', 'center'],
        handleIsSplitByWrapOnPasteCreateNewNode: () => {
          return this.$confirm(
            this.$t('edit.splitByWrap'),
            this.$t('edit.tip'),
            {
              confirmButtonText: this.$t('edit.yes'),
              cancelButtonText: this.$t('edit.no'),
              type: 'warning'
            }
          )
        },
        errorHandler: (code, err) => {
          console.error(err)
          switch (code) {
            case 'export_error':
              this.$message.error('导出失败')
              break
            default:
              break
          }
        }
      })
      if (this.openNodeRichText) this.addRichTextPlugin()
      if (this.isShowScrollbar) this.addScrollbarPlugin()
      if (this.isUseHandDrawnLikeStyle) this.addHandDrawnLikeStylePlugin()
      this.mindMap.keyCommand.addShortcut('Control+s', () => {
        this.manualSave()
      })
      // 转发事件
      ;[
        'node_active',
        'data_change',
        'view_data_change',
        'back_forward',
        'node_contextmenu',
        'node_click',
        'draw_click',
        'expand_btn_click',
        'svg_mousedown',
        'mouseup',
        'mode_change',
        'node_tree_render_end',
        'rich_text_selection_change',
        'transforming-dom-to-images',
        'generalization_node_contextmenu',
        'painter_start',
        'painter_end',
        'scrollbar_change',
        'scale'
      ].forEach(event => {
        this.mindMap.on(event, (...args) => {
          bus.emit(event, ...args)
        })
      })
      this.bindSaveEvent()
      this.testDynamicCreateNodes()
      // 如果应用被接管，那么抛出事件传递思维导图实例
      if (window.takeOverApp) {
        bus.emit('app_inited', this.mindMap)
      }
      // 解析url中的文件
      if (hasFileURL) {
        bus.emit('handle_file_url')
      }
    },
    // url中是否存在要打开的文件
    hasFileURL() {
      const fileURL = this.$route.query.fileURL
      if (!fileURL) return false
      return /\.(smm|json|xmind|md|xlsx)$/.test(fileURL)
    },

    /**
     * @Author: 王林
     * @Date: 2021-08-03 23:01:13
     * @Desc: 动态设置思维导图数据
     */
    setData(data) {
      this.handleShowLoading()
      if (data.root) {
        this.mindMap.setFullData(data)
      } else {
        this.mindMap.setData(data)
      }
      this.mindMap.view.reset()
      this.manualSave()
    },

    /**
     * @Author: 王林
     * @Date: 2021-05-05 13:32:11
     * @Desc: 重新渲染
     */
    reRender() {
      this.mindMap.reRender()
    },

    /**
     * @Author: 王林
     * @Date: 2021-05-04 13:08:28
     * @Desc: 执行命令
     */
    execCommand(...args) {
      this.mindMap.execCommand(...args)
    },

    /**
     * @Author: 王林
     * @Date: 2021-07-01 22:33:02
     * @Desc: 导出
     */
    async export(...args) {
      try {
        showLoading()
        await this.mindMap.export(...args)
        hideLoading()
      } catch (error) {
        console.log(error)
        hideLoading()
      }
    },

    // 修改导出内边距
    onPaddingChange(data) {
      this.mindMap.updateConfig(data)
    },

    // 显示新特性提示
    showNewFeatureInfo() {
      let showed = localStorage.getItem('SIMPLE_MIND_MAP_NEW_FEATURE_TIP_1')
      if (!showed) {
        this.$notify.info({
          title: this.$t('edit.newFeatureNoticeTitle'),
          message: this.$t('edit.newFeatureNoticeMessage'),
          duration: 0,
          onClose: () => {
            localStorage.setItem('SIMPLE_MIND_MAP_NEW_FEATURE_TIP_1', true)
          }
        })
      }
    },

    // 加载节点富文本编辑插件
    addRichTextPlugin() {
      if (!this.mindMap) return
      this.mindMap.addPlugin(RichText)
    },

    // 移除节点富文本编辑插件
    removeRichTextPlugin() {
      this.mindMap.removePlugin(RichText)
    },

    // 加载滚动条插件
    addScrollbarPlugin() {
      if (!this.mindMap) return
      this.mindMap.addPlugin(ScrollbarPlugin)
    },

    // 移除滚动条插件
    removeScrollbarPlugin() {
      this.mindMap.removePlugin(ScrollbarPlugin)
    },

    // 加载手绘风格插件
    addHandDrawnLikeStylePlugin() {
    },

    // 移除手绘风格插件
    removeHandDrawnLikeStylePlugin() {
    },

    // 测试动态插入节点
    testDynamicCreateNodes() {
    }
  }
}
</script>

<style lang="less" scoped>
.editContainer {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;

  .mindMapContainer {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;

    // left: 100px;
    // top: 100px;
    // right: 100px;
    // bottom: 100px;
  }
}
</style>
